{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# Braket QPU Cost Estimator\n",
    "\n",
    "Amazon Braket provides access to quantum computers, managed simulators that simulate quantum circuits, and managed notebook development environments. This notebook provides a simple function to estimate the cost of a simulation using a quantum computer and a set of cost estimate best practices to follow when submitting calculations.\n",
    "\n",
    "There are two pricing components when using a quantum computer, or quantum processing unit (QPU), on Amazon Braket: a per-shot fee and a per-task fee.\n",
    "\n",
    "A shot is a single execution of a quantum algorithm on a QPU. For example, a shot is a single pass through each stage of a complete quantum circuit on a gate-based QPU from IonQ or Rigetti. When you use a D-Wave quantum annealer, a shot is when you obtain a result sample of a quantum annealing problem. The per-shot pricing depends on the type of QPU used. The per-shot price is not affected by the number or type of gates used in a quantum circuit or the number of variables used in a quantum annealing problem.\n",
    "\n",
    "A task is a sequence of repeated shots based on the same circuit design or annealing problem. You define how many shots you want included in a task when you submit the task to Amazon Braket. Per-task pricing is the same across all QPUs.\n",
    "\n",
    "You will also be billed separately for use of each of these capabilities, as well as other AWS services that you use with Amazon Braket such as Amazon S3 for storing the results of quantum computations. The cost estimate function provided below does not account for the cost of these services. "
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# Cost Estimate Function"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "metadata": {},
   "outputs": [],
   "source": [
    "from braket.aws import AwsDevice, AwsQuantumTask"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "metadata": {},
   "outputs": [],
   "source": [
    "def estimate_cost(device=None, tasks=1, shots_per_task = 1000):\n",
    "    \"\"\"\n",
    "    Function to return the estimate cost of QPU simulation. \n",
    "\n",
    "    Input:\n",
    "        device = AwsDevice(\"AWS_QPU_ARN\")\n",
    "        \n",
    "            example: AwsDevice(\"arn:aws:braket:::device/qpu/ionq/ionQdevice\")\n",
    "            \n",
    "        tasks = maximum number of tasks allowed in a variational calculation (user defined parameter)\n",
    "        \n",
    "        shots_per_task = number of shots per task (user defined parameter)\n",
    "        \n",
    "    \n",
    "    Example output: \n",
    "        --------------------------------------------------------\n",
    "        AWS Device:       'device_name'\n",
    "        Number of tasks:  X\n",
    "        Shots per task:   XXXX\n",
    "        Price per task:   $X.X\n",
    "        Price per shot:   $X.XX\n",
    "\n",
    "        Cost estimate:    $X.XX \n",
    "        --------------------------------------------------------\n",
    "        \n",
    "    \n",
    "    Note: \n",
    "        This function calculates the cost from the number of tasks and shots. \n",
    "        It does not include the cost associated with other AWS services (Braket notebooks, S3, etc.)\n",
    "        \n",
    "    \"\"\"\n",
    "    \n",
    "    price_per_task = 0.3\n",
    "            \n",
    "    price_per_shot = device.properties.service.deviceCost.price\n",
    "    price = tasks * price_per_task \\\n",
    "          + tasks * shots_per_task * price_per_shot  \n",
    "    print('--------------------------------------------------------')\n",
    "    print('AWS Device:       {}'.format(device.name))    \n",
    "    print('Number of tasks:  {}'.format(tasks))\n",
    "    print('Shots per task:   {}'.format(shots_per_task))\n",
    "    print('Price per task:   $0.3')\n",
    "    print('Price per shot:   ${}\\n'.format(price_per_shot))\n",
    "    print('Cost estimate:    ${}'.format(price)) \n",
    "    print('--------------------------------------------------------\\n\\n')\n",
    "        "
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# Examples\n",
    "In this section we provide two common scenarios where one may want to use the cost estimator function provided above."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "metadata": {},
   "outputs": [],
   "source": [
    "# general imports\n",
    "import matplotlib.pyplot as plt\n",
    "# magic word for producing visualizations in notebook\n",
    "%matplotlib inline\n",
    "\n",
    "# AWS imports: Import Braket SDK modules\n",
    "from braket.circuits import Circuit\n",
    "from braket.devices import LocalSimulator"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "metadata": {},
   "outputs": [],
   "source": [
    "# Set the S3 bucket\n",
    "my_bucket = # TODO:  Fill in the name of the bucket\n",
    "my_prefix = \"demo\" # the name of the folder in the bucket\n",
    "s3_folder = (my_bucket, my_prefix)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Example 1 - Single Task Simulations"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "T  : |0|1|\n",
      "          \n",
      "q0 : -H-C-\n",
      "        | \n",
      "q1 : ---X-\n",
      "\n",
      "T  : |0|1|\n"
     ]
    }
   ],
   "source": [
    "# Define a Bell circuit\n",
    "bell = Circuit().h(0).cnot(0, 1)\n",
    "print(bell)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "metadata": {},
   "outputs": [],
   "source": [
    "# Set the number of shots \n",
    "n_shots = 1000"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Best practice 1: \n",
    "Estimate the cost of your simulation BEFORE submitting to the QPU."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "--------------------------------------------------------\n",
      "AWS Device:       Aspen-8\n",
      "Number of tasks:  1\n",
      "Shots per task:   1000\n",
      "Price per task:   $0.3\n",
      "Price per shot:   $0.00035\n",
      "\n",
      "Cost estimate:    $0.6499999999999999\n",
      "--------------------------------------------------------\n",
      "\n",
      "\n"
     ]
    }
   ],
   "source": [
    "# Estimate the cost of this simulation on the Rigetti device\n",
    "rigetti = AwsDevice(\"arn:aws:braket:::device/qpu/rigetti/Aspen-8\")\n",
    "estimate_cost(device = rigetti, tasks = 1, shots_per_task = n_shots)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 8,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "--------------------------------------------------------\n",
      "AWS Device:       IonQ Device\n",
      "Number of tasks:  1\n",
      "Shots per task:   1000\n",
      "Price per task:   $0.3\n",
      "Price per shot:   $0.01\n",
      "\n",
      "Cost estimate:    $10.3\n",
      "--------------------------------------------------------\n",
      "\n",
      "\n"
     ]
    }
   ],
   "source": [
    "# Estimate the cost of this simulation on the IonQ device\n",
    "ionq = AwsDevice(\"arn:aws:braket:::device/qpu/ionq/ionQdevice\")\n",
    "estimate_cost(device = ionq, tasks = 1, shots_per_task = n_shots)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Best practice 2: \n",
    "Perform a test calculation using one of the simulators to assess the quality of your algorithim under ideal conditions before using a QPU."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 9,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Counter({'11': 503, '00': 497})\n"
     ]
    },
    {
     "data": {
      "image/png": "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\n",
      "text/plain": [
       "<Figure size 432x288 with 1 Axes>"
      ]
     },
     "metadata": {
      "needs_background": "light"
     },
     "output_type": "display_data"
    }
   ],
   "source": [
    "# LocalSimulator\n",
    "device = LocalSimulator()\n",
    "result = device.run(bell, shots = n_shots).result()\n",
    "counts = result.measurement_counts\n",
    "\n",
    "# device = AwsDevice(\"arn:aws:braket:::device/quantum-simulator/amazon/sv1\")\n",
    "# device = AwsDevice(\"arn:aws:braket:::device/quantum-simulator/amazon/tn1\")\n",
    "# result = device.run(bell, s3_folder, shots = n_shots).result()\n",
    "# counts = result.measurement_counts\n",
    "\n",
    "# print counts\n",
    "print(counts)\n",
    "# plot using Counter\n",
    "plt.bar(counts.keys(), counts.values());\n",
    "plt.xlabel('bitstrings');\n",
    "plt.ylabel('counts');"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Finally, submit your task to the QPU."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# QPUs (select one only if you are comfortable with the cost calculated above)\n",
    "# device = AwsDevice(\"arn:aws:braket:::device/qpu/ionq/ionQdevice\")\n",
    "# device = AwsDevice(\"arn:aws:braket:::device/qpu/rigetti/Aspen-8\")\n",
    "# result = device.run(bell, s3_folder, shots = n_shots).result()\n",
    "# counts = result.measurement_counts\n",
    "\n",
    "# print counts\n",
    "print(counts)\n",
    "# plot using Counter\n",
    "plt.bar(counts.keys(), counts.values());\n",
    "plt.xlabel('bitstrings');\n",
    "plt.ylabel('counts');"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Example 2 - Hybrid Algorithms\n",
    "In this example we cover the best practices for implementing a hybrid algorithm (or any algorithm that require multiple iterations until a preset convergence criteria is met). For simplicity, this example will not optimize a circut parameter to minimize an objective function like is done in hybrid algorithms, e.g. the Variational Quantum Eigensolver. Instead we will define a convergence critera with little probablility of being met to highlight the importance of performing cost analysis prior to submitting calculations to the QPUs.\n",
    "\n",
    "We will utilize the Bell circuit from Example 1, but this time execute the circuit in a loop. We will define \"convergence\" (i.e. the criteria that must be met before exiting the loop) to be a sample where the effects of noise (decoherence) and other imperfections are minimal. That is, when states '01' and '10' account for less than 1% of the samples (the number of times '01' and '10' are observed are less than or equal to 10)."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Best practice 1: \n",
    "Set a maximum number of iterations to ensure the algorithm stops if convergence is not met."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 10,
   "metadata": {},
   "outputs": [],
   "source": [
    "max_iter = 100"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Best practice 2: \n",
    "Estimate the cost of your simulation BEFORE submitting to the QPU. This will provide you with an estimate of the maximum cost should you algorithm fail to converge. Based on the results of the cost estimate, select the QPU and adjust the parameters until you are comfortable with the estimated maximum cost of your simulation. "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 11,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "--------------------------------------------------------\n",
      "AWS Device:       Aspen-8\n",
      "Number of tasks:  100\n",
      "Shots per task:   1000\n",
      "Price per task:   $0.3\n",
      "Price per shot:   $0.00035\n",
      "\n",
      "Cost estimate:    $65.0\n",
      "--------------------------------------------------------\n",
      "\n",
      "\n"
     ]
    }
   ],
   "source": [
    "# Estimate the maximum cost of this simulation on the Rigetti device\n",
    "estimate_cost(device=rigetti, tasks=max_iter, shots_per_task=n_shots)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 12,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "--------------------------------------------------------\n",
      "AWS Device:       IonQ Device\n",
      "Number of tasks:  100\n",
      "Shots per task:   1000\n",
      "Price per task:   $0.3\n",
      "Price per shot:   $0.01\n",
      "\n",
      "Cost estimate:    $1030.0\n",
      "--------------------------------------------------------\n",
      "\n",
      "\n"
     ]
    }
   ],
   "source": [
    "# Estimate the maximum cost of this simulation on the IonQ device\n",
    "estimate_cost(device=ionq, tasks=max_iter, shots_per_task=n_shots)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Best practice 3:\n",
    "Perform a test calculation using one of the simulators to assess the quality of your algorithim under ideal conditions before using a QPU."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 13,
   "metadata": {},
   "outputs": [],
   "source": [
    "# Simulators \n",
    "device = LocalSimulator()\n",
    "# device = AwsDevice(\"arn:aws:braket:::device/quantum-simulator/amazon/sv1\")\n",
    "# device = AwsDevice(\"arn:aws:braket:::device/quantum-simulator/amazon/tn1\")\n",
    "\n",
    "# QPUs (select one only if you are comfortable with the cost calculated above)\n",
    "# device = AwsDevice(\"arn:aws:braket:::device/qpu/ionq/ionQdevice\")\n",
    "# device = AwsDevice(\"arn:aws:braket:::device/qpu/rigetti/Aspen-8\")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 14,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "calculation \"converged\"\n"
     ]
    }
   ],
   "source": [
    "for i in range(max_iter):\n",
    "    \n",
    "    # Run circuit (execute a SINGLE task with 1000 shots)\n",
    "    \n",
    "    # Submit to the LocalSimulator\n",
    "    result = device.run(bell, shots = n_shots).result()\n",
    "    \n",
    "    # Submit to a QPU, SV1, or TN1\n",
    "    # (use the QPU only if you are comfortable with the cost calculated above)\n",
    "    # result = device.run(bell, s3_folder, shots = n_shots).result()\n",
    "    \n",
    "    # get measurement shots\n",
    "    counts = result.measurement_counts\n",
    "    \n",
    "    # Check convergence criteria\n",
    "    if counts['01'] + counts['10'] <= 10:\n",
    "        print('calculation \"converged\"')\n",
    "        break\n",
    "        "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": []
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "conda_braket",
   "language": "python",
   "name": "conda_braket"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.7.10"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 4
}
